-- task_mgr.lua
-- 任务管理器
-- 管理异步执行的任务

declare_module('TASK_MGR')

require('task')
require('object.task')

-- 所有任务
local m_tasks=  {}

-- 用户分配的下一个taskid
local m_allocated_id = 1000;

-- 用于执行简单任务的task
local m_dispatch_task = nil;

-- 任务派遣ID
local m_dispatch_id = 0;

-- 派遣任务的callback列表
local m_dispatch_callbacks = {}

-- 初始化dispatch_task
local function init_dispatch_task()
    local update_freq = 10;
    m_dispatch_task = task.create('scripts/lua_pf/dispatch_task.lua', {task.id(), update_freq}); 
    logger:info('Init dispatch id: '..tostring(m_dispatch_task));
end

-- 分配任务ID
local function alloc_task_id()
    while m_tasks[m_allocated_id] ~= nil do
       m_allocated_id = m_allocated_id + 1;
    end

    local res = m_allocated_id;
    m_allocated_id = (m_allocated_id + 1) % 9999999 + 1000;
    return res;
end

-- 创建任务
function create_task(script, params)

    -- save参数为string
    local _params = nil; 
    if params then
        _params = table.fast_save(params);
    end

    -- 创建task
    local taskkey = alloc_task_id();
    local taskid = task.create('scripts/lua_pf/taskloader.lua', {taskkey, task.id(), script, _params}); 
    if taskid > 0 then
        logger:info(string.format('Task (%d) created', taskid));
        local task = Task(taskkey, taskid);
        if m_tasks[taskkey] ~= nil then
            logger:warn('The old task is still exist while create a new');
            delete_task(taskkey);
        end
        m_tasks[taskkey] = task;
        return task;
    else
        return nil, taskid;
    end
end

-- 派遣一个任务，会插入到默认的任务队列中
function dispatch_task(script, params, callback)

    m_dispatch_id = m_dispatch_id + 1;
    local task_info = {
        id = m_dispatch_id,
        script = script;
        params = params,
    }

    -- send到dispatch_task中执行
    task.post(m_dispatch_task, table.fast_save(task_info));

    -- 填入callback
    m_dispatch_callbacks[m_dispatch_id] = callback;

    -- 返回id
    return m_dispatch_id;
end

-- 暂停任务
function pause_task(task)
    logger:error('not supported yet.');
end

-- 删除任务
function delete_task(taskkey)
    logger:info(string.format('Task (%d) destroyed', taskkey));
    local task = m_tasks[taskkey];
    if task ~= nil then
        destroy_object(task);
        m_tasks[taskkey] = nil;
    end
end

-- 任务向外部传递消息
function post_message(target_task_id, taskkey, msg_id, ...)
    -- 组织传送的数据
    local send_content = {
        msg_id,
        task.id(),
        taskkey,
        {...},
    }

    local res = task.post(target_task_id, table.fast_save(send_content));
    if res == -1 then
        return false, 'task is not running';
    elseif res == -2 then
        return false, 'can not malloc message entry';
    else
        return true;
    end
end

-- 检查任务回信的线程
function _check_mailbox()
    while true do
        local msg, flag, rc = task.receive(0);
        if rc == 0 then
            local content = table.fast_load(msg);
            local task_msg_id = content[1];
            local task_id_from = content[2];
            local task_key = content[3];
            local msg = content[4];

            if task_key == m_dispatch_task then
                -- 是dipatch_task，处理一下
                local dispatch_id, dispatch_res = unpack(msg);
                local callback = m_dispatch_callbacks[dispatch_id];
                if callback then
                    safe_call(callback, dispatch_id, task_msg_id, dispatch_res);
                    m_dispatch_callbacks[dispatch_id] = nil;
                end
            else
                -- 是普通的其他task
                local task = m_tasks[task_key];
                if task ~= nil then
                    safe_call(task._notify_msg_receive, task, task_msg_id, unpack(msg));
                    -- task:_notify_msg_receive(task_msg_id, unpack(msg));
                else
                    logger:warn('Receive an task msg from an unexist task');
                end
            end
        end

        sleep(0);
    end
end

-- 仅在主线程需要做这些事情
if task.id() == 1 then
    -- 创建dispatch_task
    init_dispatch_task();

    -- 创建检查任信箱的线程
    THREAD_MGR.create_thread(_check_mailbox);
end

